#include <boost/variant.hpp>
#include <xmmsclient/xmmsclient++.h>
#include "xmmsqt4.h"
#include "audioclient.h"


AudioClient::AudioClient() : client_("qtport")
{
    client_.connect(std::getenv("XMMS_PATH"));
    client_.setMainloop(new XmmsQT4(client_.getConnection()));
    client_.playback.currentID()(Xmms::bind(&AudioClient::updateCurrentPlaybackInfo, this));
    client_.playback.broadcastCurrentID()(Xmms::bind(&AudioClient::updateCurrentPlaybackInfo, this));
    client_.playback.broadcastStatus()(Xmms::bind(&AudioClient::updateStatus, this));
    client_.playback.signalPlaytime()(Xmms::bind(&AudioClient::playtimeSignal, this));

    client_.playlist.broadcastChanged()(Xmms::bind(&AudioClient::playlistChangedSignal, this));
    client_.playlist.broadcastCurrentPos()(Xmms::bind(&AudioClient::updateCurrentPosition, this));
}

void AudioClient::add(const QString& fileName){
    std::string url = "file://" + fileName.toStdString();
    try{
        client_.playlist.addUrl(url);
    }
    catch (Xmms::result_error& err){
        std::cout << "could not add!: " << err.what() << std::endl;
    }
}

void AudioClient::clear(){
    client_.playlist.clear();
}

void AudioClient::play(){
    client_.playback.start();
}

void AudioClient::play(const QModelIndex& index){
    int position = index.row();
    client_.playlist.setNext( position );
    client_.playback.tickle();
}

void AudioClient::pause(){
    client_.playback.pause();
}

void AudioClient::stop(){
    client_.playback.stop();
}

void AudioClient::next(){
    client_.playlist.setNextRel(1);
    client_.playback.tickle();
}

void AudioClient::prev(){
    client_.playlist.setNextRel(-1);
    client_.playback.tickle();
}

void AudioClient::playlistRemoveEntry(const int &position){
    client_.playlist.removeEntry(position);
}

void AudioClient::seek(const int& milliseconds){
    client_.playback.seekMs(milliseconds);
}

void AudioClient::setPlaylistModel(QStandardItemModel* model){
    model_ = model;
}

void AudioClient::loadPlaylist(){
    client_.playlist.listEntries()(Xmms::bind(&AudioClient::loadPlaylistEntries, this));
}

bool AudioClient::appendToModel(const Xmms::PropDict& propdict){
    QList< QStandardItem* > entry;
    QString title, album, artist;
    extractQStringFromDict(title, propdict, "title");
    extractQStringFromDict(album, propdict, "album");
    extractQStringFromDict(artist, propdict, "artist");

    if (title.simplified().isEmpty())
        extractQStringFromDict(title, propdict, "url");

    QStandardItem* title_i = new QStandardItem(title);
    QStandardItem* album_i = new QStandardItem(album);
    QStandardItem* artist_i = new QStandardItem(artist);

    entry << title_i << album_i << artist_i;
    model_->appendRow(entry);

    return true;
}

bool AudioClient::loadPlaylistEntries(const Xmms::List< unsigned int >& list){
    for(list.first(); list.isValid(); ++list){
        client_.medialib.getInfo(*list)(Xmms::bind(&AudioClient::appendToModel, this));
    }
    return true;
}

void AudioClient::extractQStringFromDict(QString& recipient, const Xmms::PropDict& dict, const std::string& key){
    std::string value;
    try{
        value = boost::get< std::string >(dict[key]);
    }
    catch (Xmms::no_such_key_error& err){
        value = "";
    }
    recipient.clear();
    recipient.append(value.c_str());
}

bool AudioClient::playtimeSignal(const unsigned int& playtimeValue){
    emit(playtime(playtimeValue));
    return true;
}

bool AudioClient::updateCurrentPlaybackInfo(const unsigned int& id){
    client_.medialib.getInfo(id)(Xmms::bind(&AudioClient::updateCurrentPlaybackInfoFromDict, this));
    return true;
}

bool AudioClient::updateCurrentPlaybackInfoFromDict(const Xmms::PropDict& info){
    int duration = 0;
    try{
        duration = boost::get<int>(info["duration"]);
    }
    catch (...){
        std::cout << "[error] duration not set for this stream:" << std::endl;
    }
    emit(currentSongDuration(duration));
    return true;
}

bool AudioClient::updateCurrentPosition(const Xmms::Dict& positionDict){
    unsigned int position = positionDict.get<unsigned int> ("position");
    emit(currentPosition(position));
    return true;
}

bool AudioClient::updateStatus(const Xmms::Playback::Status& status){
    if (status == Xmms::Playback::STOPPED)
        emit(playtime(0));
    return true;
}

bool AudioClient::playlistChangedSignal(const Xmms::Dict& playlistChange){
    int32_t changeType = playlistChange.get<int32_t>("type");
    int32_t position = 0, newPosition = 0;
    uint32_t id = 0;
    std::string playlistName_s;
    QString playlistName;

    if (playlistChange.contains ("position")) {
        position = playlistChange.get<int32_t> ("position");
    }

    if (playlistChange.contains ("id")) {
        id = playlistChange.get<uint32_t> ("id");
    }

    if (playlistChange.contains ("name")) {
        playlistName_s = playlistChange.get<std::string> ("name");
    }

    //if (s != m_name) {
    //    return true;
    //}

    switch (changeType){
        case XMMS_PLAYLIST_CHANGED_ADD:
            client_.medialib.getInfo(id)(Xmms::bind(&AudioClient::appendToModel, this));
            break;

        case XMMS_PLAYLIST_CHANGED_CLEAR:
            emit(playlistCleared());
            break;

        case XMMS_PLAYLIST_CHANGED_REMOVE:
            emit(removedEntry(position));
            break;
    }

    return true;
}
